﻿namespace DotNetCommon
{
    using System;
    using System.IO;

    /// <summary>
    /// Base64的扩展算法,保证Url安全(jwt就是用的这种算法)，原生的base64转换参考：<seealso cref="Convert.ToBase64String(byte[])"/>
    /// </summary>
    /// <remarks>
    /// <para>原理是将Base64编码中的 '<c>+</c>' 和 '<c>/</c>' 替换为 '<c>-</c>' 和 '<c>_</c>'， 并去掉末尾的 '<c>=</c>',这样编码后的字符串仅包含 <c>0-9A-Za-z</c> 以及 '<c>-</c>' 和 '<c>_</c>'
    /// </para>
    /// </remarks>
    public static class Base64UrlSafe
    {
        /// <summary>
        /// 将给定的<see langword="byte[]"/>编码为URL和文件安全的Base64编码字符串。
        /// </summary>
        /// <param name="arg">编码参数</param>
        /// <returns>编码结果为字符串</returns>
        public static string Encode(byte[] arg)
        {
            var s = Convert.ToBase64String(arg); // 标准base64解码

            s = s.Split('=')[0]; // Remove any trailing '='s
            s = s.Replace('+', '-'); // 编码的第62个字符
            s = s.Replace('/', '_'); // 编码的第63个字符
            return s;
        }

        /// <summary>
        /// 将给定的URL和文件安全的Base64字符串解码为
        /// <see langword="byte"/>[]。
        /// </summary>
        /// <param name="arg">解码参数</param>
        /// <returns>解码结果为<see langword="byte"/>[]</returns>
        /// <exception cref="InvalidDataException">
        /// 当给定的<paramref name="arg"/>不是一个有效的Base64编码字符串时抛出。
        /// </exception>
        public static byte[] Decode(string arg)
        {
            Ensure.NotNullOrEmptyOrWhiteSpace(arg);

            var s = arg;
            s = s.Replace('-', '+'); // 编码的第62个字符
            s = s.Replace('_', '/'); // 编码的第63个字符

            // 用尾随'='s填充
            switch (s.Length % 4)
            {
                case 0: break; // 这种情况没有填充字符
                case 2:
                    s += "==";
                    break; // 两个填充字符
                case 3:
                    s += "=";
                    break; // 一个填充字符
                default: throw new InvalidDataException("Invalid Base64UrlSafe encoded string.");
            }

            return Convert.FromBase64String(s); // 标准base64解码
        }
    }
}
